﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using System.Reflection;
using System.Diagnostics;

namespace FishServe.Core
{
    public abstract class Module
    {
        private bool _initialised = false;
        private IUnityContainer _container;
        private ModuleLoader _moduleLoader;
        private ModuleManifestResolver _moduleManifestResolver;
        private ModuleManifest _moduleManifest;
        
        //[Dependency]
        //public ModuleLoader ModuleLoader
        //{
        //    set 
        //    {
        //        if (_moduleLoader != value)
        //        {
        //            _moduleLoader = value;
        //            if (_moduleManifestResolver != null && _moduleLoader != null)
        //                RegisterRegisteredTypes();
        //        }
        //    }

        //}

        //[Dependency]
        //public ModuleManifestResolver ModuleManifestResolver
        //{
        //    set 
        //    {
        //        if (_moduleManifestResolver != value)
        //        {
        //            _moduleManifestResolver = value;
        //            if (_moduleManifestResolver != null && _moduleLoader != null)
        //                RegisterRegisteredTypes();
        //        }
        //    }
        //}

        public IUnityContainer Container
        {
            get { return _container; }
        }

        public Module(ModuleLoader moduleLoader, ModuleManifestResolver moduleManifestResolver) 
        {
            _container = new UnityContainer();
            _moduleLoader = moduleLoader;
            _container.RegisterInstance<ModuleLoader>(_moduleLoader);
            _moduleManifestResolver = moduleManifestResolver;
            _container.RegisterInstance<ModuleManifestResolver>(_moduleManifestResolver);
            RegisterRegisteredTypes();
        }

        //[InjectionConstructor]
        public Module(IUnityContainer container)
        {
            _container = container;
            _moduleLoader = _container.Resolve<ModuleLoader>();
            _moduleManifestResolver = _container.Resolve<ModuleManifestResolver>();
            RegisterRegisteredTypes();
        }

        protected void RegisterRegisteredTypes()
        {
            if (_initialised)
                return;

            _initialised = true;

            if( _moduleLoader == null )
                _moduleLoader = _container.Resolve<ModuleLoader>();

            if( _moduleManifestResolver == null )
                _moduleManifestResolver = _container.Resolve<ModuleManifestResolver>();

            _moduleManifest = _moduleManifestResolver.GetModuleManifest(this);

            foreach (ManifestRegisteredTypeInfo registeredTypeInfo in _moduleManifest.RegisteredTypes)
            {
                Assembly fromModule = _moduleLoader.LoadModule(registeredTypeInfo.FromTypeInfo);
                Assembly toModule = _moduleLoader.LoadModule(registeredTypeInfo.ToTypeInfo);

                Type fromType = fromModule.GetType(registeredTypeInfo.FromTypeInfo.TypeName);
                Type toType = toModule.GetType(registeredTypeInfo.ToTypeInfo.TypeName);

                if (registeredTypeInfo.Lifetime == RegisteredTypeLifetime.Singleton)
                {
                    if( _container.Parent != null )
                        _container.Parent.RegisterType(fromType, toType, new ContainerControlledLifetimeManager());
                    else
                        _container.RegisterType(fromType, toType, new ContainerControlledLifetimeManager() );
                }
                else
                {
                    if( _container.Parent != null )
                        _container.Parent.RegisterType(fromType, toType, new ContainerControlledLifetimeManager());
                    else
                        _container.RegisterType(fromType, toType, new ContainerControlledLifetimeManager() );
                }
                //    RegisterSingletonType(fromType, toType);
                //else
                //    RegisterType(fromType, toType);
                    
            }
        }

        protected void RegisterSingletonInstance<T>( T instance )
        {
            _container.RegisterInstance<T>(instance);
        }

        protected void RegisterSingletonType<TFrom, TTo>() where TTo : TFrom
        {
            _container.RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager());
        }

        protected void RegisterSingletonType(Type fromType, Type toType) 
        {
            _container.RegisterType( fromType, toType, new ContainerControlledLifetimeManager());
        }

        protected void RegisterType(Type fromType, Type toType)
        {
            _container.RegisterType(fromType, toType);
        }
    }
}
